home *** CD-ROM | disk | FTP | other *** search
/ Personal Computer World 2009 February / PCWFEB09.iso / Software / Linux / Kubuntu 8.10 / kubuntu-8.10-desktop-i386.iso / casper / filesystem.squashfs / usr / lib / python2.5 / SimpleXMLRPCServer.pyc (.txt) < prev    next >
Python Compiled Bytecode  |  2008-10-29  |  19KB  |  530 lines

  1. # Source Generated with Decompyle++
  2. # File: in.pyc (Python 2.5)
  3.  
  4. '''Simple XML-RPC Server.
  5.  
  6. This module can be used to create simple XML-RPC servers
  7. by creating a server and either installing functions, a
  8. class instance, or by extending the SimpleXMLRPCServer
  9. class.
  10.  
  11. It can also be used to handle XML-RPC requests in a CGI
  12. environment using CGIXMLRPCRequestHandler.
  13.  
  14. A list of possible usage patterns follows:
  15.  
  16. 1. Install functions:
  17.  
  18. server = SimpleXMLRPCServer(("localhost", 8000))
  19. server.register_function(pow)
  20. server.register_function(lambda x,y: x+y, \'add\')
  21. server.serve_forever()
  22.  
  23. 2. Install an instance:
  24.  
  25. class MyFuncs:
  26.     def __init__(self):
  27.         # make all of the string functions available through
  28.         # string.func_name
  29.         import string
  30.         self.string = string
  31.     def _listMethods(self):
  32.         # implement this method so that system.listMethods
  33.         # knows to advertise the strings methods
  34.         return list_public_methods(self) +                 [\'string.\' + method for method in list_public_methods(self.string)]
  35.     def pow(self, x, y): return pow(x, y)
  36.     def add(self, x, y) : return x + y
  37.  
  38. server = SimpleXMLRPCServer(("localhost", 8000))
  39. server.register_introspection_functions()
  40. server.register_instance(MyFuncs())
  41. server.serve_forever()
  42.  
  43. 3. Install an instance with custom dispatch method:
  44.  
  45. class Math:
  46.     def _listMethods(self):
  47.         # this method must be present for system.listMethods
  48.         # to work
  49.         return [\'add\', \'pow\']
  50.     def _methodHelp(self, method):
  51.         # this method must be present for system.methodHelp
  52.         # to work
  53.         if method == \'add\':
  54.             return "add(2,3) => 5"
  55.         elif method == \'pow\':
  56.             return "pow(x, y[, z]) => number"
  57.         else:
  58.             # By convention, return empty
  59.             # string if no help is available
  60.             return ""
  61.     def _dispatch(self, method, params):
  62.         if method == \'pow\':
  63.             return pow(*params)
  64.         elif method == \'add\':
  65.             return params[0] + params[1]
  66.         else:
  67.             raise \'bad method\'
  68.  
  69. server = SimpleXMLRPCServer(("localhost", 8000))
  70. server.register_introspection_functions()
  71. server.register_instance(Math())
  72. server.serve_forever()
  73.  
  74. 4. Subclass SimpleXMLRPCServer:
  75.  
  76. class MathServer(SimpleXMLRPCServer):
  77.     def _dispatch(self, method, params):
  78.         try:
  79.             # We are forcing the \'export_\' prefix on methods that are
  80.             # callable through XML-RPC to prevent potential security
  81.             # problems
  82.             func = getattr(self, \'export_\' + method)
  83.         except AttributeError:
  84.             raise Exception(\'method "%s" is not supported\' % method)
  85.         else:
  86.             return func(*params)
  87.  
  88.     def export_add(self, x, y):
  89.         return x + y
  90.  
  91. server = MathServer(("localhost", 8000))
  92. server.serve_forever()
  93.  
  94. 5. CGI script:
  95.  
  96. server = CGIXMLRPCRequestHandler()
  97. server.register_function(pow)
  98. server.handle_request()
  99. '''
  100. import xmlrpclib
  101. from xmlrpclib import Fault
  102. import SocketServer
  103. import BaseHTTPServer
  104. import sys
  105. import os
  106.  
  107. try:
  108.     import fcntl
  109. except ImportError:
  110.     fcntl = None
  111.  
  112.  
  113. def resolve_dotted_attribute(obj, attr, allow_dotted_names = True):
  114.     """resolve_dotted_attribute(a, 'b.c.d') => a.b.c.d
  115.  
  116.     Resolves a dotted attribute name to an object.  Raises
  117.     an AttributeError if any attribute in the chain starts with a '_'.
  118.  
  119.     If the optional allow_dotted_names argument is false, dots are not
  120.     supported and this function operates similar to getattr(obj, attr).
  121.     """
  122.     if allow_dotted_names:
  123.         attrs = attr.split('.')
  124.     else:
  125.         attrs = [
  126.             attr]
  127.     for i in attrs:
  128.         if i.startswith('_'):
  129.             raise AttributeError('attempt to access private attribute "%s"' % i)
  130.             continue
  131.         obj = getattr(obj, i)
  132.     
  133.     return obj
  134.  
  135.  
  136. def list_public_methods(obj):
  137.     '''Returns a list of attribute strings, found in the specified
  138.     object, which represent callable attributes'''
  139.     return _[1]
  140.  
  141.  
  142. def remove_duplicates(lst):
  143.     '''remove_duplicates([2,2,2,1,3,3]) => [3,1,2]
  144.  
  145.     Returns a copy of a list without duplicates. Every list
  146.     item must be hashable and the order of the items in the
  147.     resulting list is not defined.
  148.     '''
  149.     u = { }
  150.     for x in lst:
  151.         u[x] = 1
  152.     
  153.     return u.keys()
  154.  
  155.  
  156. class SimpleXMLRPCDispatcher:
  157.     '''Mix-in class that dispatches XML-RPC requests.
  158.  
  159.     This class is used to register XML-RPC method handlers
  160.     and then to dispatch them. There should never be any
  161.     reason to instantiate this class directly.
  162.     '''
  163.     
  164.     def __init__(self, allow_none, encoding):
  165.         self.funcs = { }
  166.         self.instance = None
  167.         self.allow_none = allow_none
  168.         self.encoding = encoding
  169.  
  170.     
  171.     def register_instance(self, instance, allow_dotted_names = False):
  172.         """Registers an instance to respond to XML-RPC requests.
  173.  
  174.         Only one instance can be installed at a time.
  175.  
  176.         If the registered instance has a _dispatch method then that
  177.         method will be called with the name of the XML-RPC method and
  178.         its parameters as a tuple
  179.         e.g. instance._dispatch('add',(2,3))
  180.  
  181.         If the registered instance does not have a _dispatch method
  182.         then the instance will be searched to find a matching method
  183.         and, if found, will be called. Methods beginning with an '_'
  184.         are considered private and will not be called by
  185.         SimpleXMLRPCServer.
  186.  
  187.         If a registered function matches a XML-RPC request, then it
  188.         will be called instead of the registered instance.
  189.  
  190.         If the optional allow_dotted_names argument is true and the
  191.         instance does not have a _dispatch method, method names
  192.         containing dots are supported and resolved, as long as none of
  193.         the name segments start with an '_'.
  194.  
  195.             *** SECURITY WARNING: ***
  196.  
  197.             Enabling the allow_dotted_names options allows intruders
  198.             to access your module's global variables and may allow
  199.             intruders to execute arbitrary code on your machine.  Only
  200.             use this option on a secure, closed network.
  201.  
  202.         """
  203.         self.instance = instance
  204.         self.allow_dotted_names = allow_dotted_names
  205.  
  206.     
  207.     def register_function(self, function, name = None):
  208.         '''Registers a function to respond to XML-RPC requests.
  209.  
  210.         The optional name argument can be used to set a Unicode name
  211.         for the function.
  212.         '''
  213.         if name is None:
  214.             name = function.__name__
  215.         
  216.         self.funcs[name] = function
  217.  
  218.     
  219.     def register_introspection_functions(self):
  220.         '''Registers the XML-RPC introspection methods in the system
  221.         namespace.
  222.  
  223.         see http://xmlrpc.usefulinc.com/doc/reserved.html
  224.         '''
  225.         self.funcs.update({
  226.             'system.listMethods': self.system_listMethods,
  227.             'system.methodSignature': self.system_methodSignature,
  228.             'system.methodHelp': self.system_methodHelp })
  229.  
  230.     
  231.     def register_multicall_functions(self):
  232.         '''Registers the XML-RPC multicall method in the system
  233.         namespace.
  234.  
  235.         see http://www.xmlrpc.com/discuss/msgReader$1208'''
  236.         self.funcs.update({
  237.             'system.multicall': self.system_multicall })
  238.  
  239.     
  240.     def _marshaled_dispatch(self, data, dispatch_method = None):
  241.         '''Dispatches an XML-RPC method from marshalled (XML) data.
  242.  
  243.         XML-RPC methods are dispatched from the marshalled (XML) data
  244.         using the _dispatch method and the result is returned as
  245.         marshalled data. For backwards compatibility, a dispatch
  246.         function can be provided as an argument (see comment in
  247.         SimpleXMLRPCRequestHandler.do_POST) but overriding the
  248.         existing method through subclassing is the prefered means
  249.         of changing method dispatch behavior.
  250.         '''
  251.         
  252.         try:
  253.             (params, method) = xmlrpclib.loads(data)
  254.             if dispatch_method is not None:
  255.                 response = dispatch_method(method, params)
  256.             else:
  257.                 response = self._dispatch(method, params)
  258.             response = (response,)
  259.             response = xmlrpclib.dumps(response, methodresponse = 1, allow_none = self.allow_none, encoding = self.encoding)
  260.         except Fault:
  261.             fault = None
  262.             response = xmlrpclib.dumps(fault, allow_none = self.allow_none, encoding = self.encoding)
  263.         except:
  264.             response = xmlrpclib.dumps(xmlrpclib.Fault(1, '%s:%s' % (sys.exc_type, sys.exc_value)), encoding = self.encoding, allow_none = self.allow_none)
  265.  
  266.         return response
  267.  
  268.     
  269.     def system_listMethods(self):
  270.         """system.listMethods() => ['add', 'subtract', 'multiple']
  271.  
  272.         Returns a list of the methods supported by the server."""
  273.         methods = self.funcs.keys()
  274.         if self.instance is not None:
  275.             if hasattr(self.instance, '_listMethods'):
  276.                 methods = remove_duplicates(methods + self.instance._listMethods())
  277.             elif not hasattr(self.instance, '_dispatch'):
  278.                 methods = remove_duplicates(methods + list_public_methods(self.instance))
  279.             
  280.         
  281.         methods.sort()
  282.         return methods
  283.  
  284.     
  285.     def system_methodSignature(self, method_name):
  286.         """system.methodSignature('add') => [double, int, int]
  287.  
  288.         Returns a list describing the signature of the method. In the
  289.         above example, the add method takes two integers as arguments
  290.         and returns a double result.
  291.  
  292.         This server does NOT support system.methodSignature."""
  293.         return 'signatures not supported'
  294.  
  295.     
  296.     def system_methodHelp(self, method_name):
  297.         '''system.methodHelp(\'add\') => "Adds two integers together"
  298.  
  299.         Returns a string containing documentation for the specified method.'''
  300.         method = None
  301.         if self.funcs.has_key(method_name):
  302.             method = self.funcs[method_name]
  303.         elif self.instance is not None:
  304.             None if hasattr(self.instance, '_methodHelp') else None<EXCEPTION MATCH>AttributeError
  305.         
  306.         if method is None:
  307.             return ''
  308.         else:
  309.             import pydoc as pydoc
  310.             return pydoc.getdoc(method)
  311.  
  312.     
  313.     def system_multicall(self, call_list):
  314.         """system.multicall([{'methodName': 'add', 'params': [2, 2]}, ...]) => [[4], ...]
  315.  
  316.         Allows the caller to package multiple XML-RPC calls into a single
  317.         request.
  318.  
  319.         See http://www.xmlrpc.com/discuss/msgReader$1208
  320.         """
  321.         results = []
  322.         for call in call_list:
  323.             method_name = call['methodName']
  324.             params = call['params']
  325.             
  326.             try:
  327.                 results.append([
  328.                     self._dispatch(method_name, params)])
  329.             continue
  330.             except Fault:
  331.                 fault = None
  332.                 results.append({
  333.                     'faultCode': fault.faultCode,
  334.                     'faultString': fault.faultString })
  335.                 continue
  336.                 results.append({
  337.                     'faultCode': 1,
  338.                     'faultString': '%s:%s' % (sys.exc_type, sys.exc_value) })
  339.                 continue
  340.             
  341.  
  342.         
  343.         return results
  344.  
  345.     
  346.     def _dispatch(self, method, params):
  347.         """Dispatches the XML-RPC method.
  348.  
  349.         XML-RPC calls are forwarded to a registered function that
  350.         matches the called XML-RPC method name. If no such function
  351.         exists then the call is forwarded to the registered instance,
  352.         if available.
  353.  
  354.         If the registered instance has a _dispatch method then that
  355.         method will be called with the name of the XML-RPC method and
  356.         its parameters as a tuple
  357.         e.g. instance._dispatch('add',(2,3))
  358.  
  359.         If the registered instance does not have a _dispatch method
  360.         then the instance will be searched to find a matching method
  361.         and, if found, will be called.
  362.  
  363.         Methods beginning with an '_' are considered private and will
  364.         not be called.
  365.         """
  366.         func = None
  367.         
  368.         try:
  369.             func = self.funcs[method]
  370.         except KeyError:
  371.             if self.instance is not None:
  372.                 pass
  373.             None if hasattr(self.instance, '_dispatch') else None<EXCEPTION MATCH>AttributeError
  374.  
  375.         if func is not None:
  376.             return func(*params)
  377.         else:
  378.             raise Exception('method "%s" is not supported' % method)
  379.  
  380.  
  381.  
  382. class SimpleXMLRPCRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
  383.     '''Simple XML-RPC request handler class.
  384.  
  385.     Handles all HTTP POST requests and attempts to decode them as
  386.     XML-RPC requests.
  387.     '''
  388.     rpc_paths = ('/', '/RPC2')
  389.     
  390.     def is_rpc_path_valid(self):
  391.         if self.rpc_paths:
  392.             return self.path in self.rpc_paths
  393.         else:
  394.             return True
  395.  
  396.     
  397.     def do_POST(self):
  398.         """Handles the HTTP POST request.
  399.  
  400.         Attempts to interpret all HTTP POST requests as XML-RPC calls,
  401.         which are forwarded to the server's _dispatch method for handling.
  402.         """
  403.         if not self.is_rpc_path_valid():
  404.             self.report_404()
  405.             return None
  406.         
  407.         
  408.         try:
  409.             max_chunk_size = 10485760
  410.             size_remaining = int(self.headers['content-length'])
  411.             L = []
  412.             while size_remaining:
  413.                 chunk_size = min(size_remaining, max_chunk_size)
  414.                 L.append(self.rfile.read(chunk_size))
  415.                 size_remaining -= len(L[-1])
  416.             data = ''.join(L)
  417.             response = self.server._marshaled_dispatch(data, getattr(self, '_dispatch', None))
  418.         except:
  419.             self.send_response(500)
  420.             self.end_headers()
  421.  
  422.         self.send_response(200)
  423.         self.send_header('Content-type', 'text/xml')
  424.         self.send_header('Content-length', str(len(response)))
  425.         self.end_headers()
  426.         self.wfile.write(response)
  427.         self.wfile.flush()
  428.         self.connection.shutdown(1)
  429.  
  430.     
  431.     def report_404(self):
  432.         self.send_response(404)
  433.         response = 'No such page'
  434.         self.send_header('Content-type', 'text/plain')
  435.         self.send_header('Content-length', str(len(response)))
  436.         self.end_headers()
  437.         self.wfile.write(response)
  438.         self.wfile.flush()
  439.         self.connection.shutdown(1)
  440.  
  441.     
  442.     def log_request(self, code = '-', size = '-'):
  443.         '''Selectively log an accepted request.'''
  444.         if self.server.logRequests:
  445.             BaseHTTPServer.BaseHTTPRequestHandler.log_request(self, code, size)
  446.         
  447.  
  448.  
  449.  
  450. class SimpleXMLRPCServer(SocketServer.TCPServer, SimpleXMLRPCDispatcher):
  451.     '''Simple XML-RPC server.
  452.  
  453.     Simple XML-RPC server that allows functions and a single instance
  454.     to be installed to handle requests. The default implementation
  455.     attempts to dispatch XML-RPC calls to the functions or instance
  456.     installed in the server. Override the _dispatch method inhereted
  457.     from SimpleXMLRPCDispatcher to change this behavior.
  458.     '''
  459.     allow_reuse_address = True
  460.     
  461.     def __init__(self, addr, requestHandler = SimpleXMLRPCRequestHandler, logRequests = True, allow_none = False, encoding = None):
  462.         self.logRequests = logRequests
  463.         SimpleXMLRPCDispatcher.__init__(self, allow_none, encoding)
  464.         SocketServer.TCPServer.__init__(self, addr, requestHandler)
  465.         if fcntl is not None and hasattr(fcntl, 'FD_CLOEXEC'):
  466.             flags = fcntl.fcntl(self.fileno(), fcntl.F_GETFD)
  467.             flags |= fcntl.FD_CLOEXEC
  468.             fcntl.fcntl(self.fileno(), fcntl.F_SETFD, flags)
  469.         
  470.  
  471.  
  472.  
  473. class CGIXMLRPCRequestHandler(SimpleXMLRPCDispatcher):
  474.     '''Simple handler for XML-RPC data passed through CGI.'''
  475.     
  476.     def __init__(self, allow_none = False, encoding = None):
  477.         SimpleXMLRPCDispatcher.__init__(self, allow_none, encoding)
  478.  
  479.     
  480.     def handle_xmlrpc(self, request_text):
  481.         '''Handle a single XML-RPC request'''
  482.         response = self._marshaled_dispatch(request_text)
  483.         print 'Content-Type: text/xml'
  484.         print 'Content-Length: %d' % len(response)
  485.         print 
  486.         sys.stdout.write(response)
  487.  
  488.     
  489.     def handle_get(self):
  490.         '''Handle a single HTTP GET request.
  491.  
  492.         Default implementation indicates an error because
  493.         XML-RPC uses the POST method.
  494.         '''
  495.         code = 400
  496.         (message, explain) = BaseHTTPServer.BaseHTTPRequestHandler.responses[code]
  497.         response = BaseHTTPServer.DEFAULT_ERROR_MESSAGE % {
  498.             'code': code,
  499.             'message': message,
  500.             'explain': explain }
  501.         print 'Status: %d %s' % (code, message)
  502.         print 'Content-Type: text/html'
  503.         print 'Content-Length: %d' % len(response)
  504.         print 
  505.         sys.stdout.write(response)
  506.  
  507.     
  508.     def handle_request(self, request_text = None):
  509.         '''Handle a single XML-RPC request passed through a CGI post method.
  510.  
  511.         If no XML data is given then it is read from stdin. The resulting
  512.         XML-RPC response is printed to stdout along with the correct HTTP
  513.         headers.
  514.         '''
  515.         if request_text is None and os.environ.get('REQUEST_METHOD', None) == 'GET':
  516.             self.handle_get()
  517.         elif request_text is None:
  518.             request_text = sys.stdin.read()
  519.         
  520.         self.handle_xmlrpc(request_text)
  521.  
  522.  
  523. if __name__ == '__main__':
  524.     print 'Running XML-RPC server on port 8000'
  525.     server = SimpleXMLRPCServer(('localhost', 8000))
  526.     server.register_function(pow)
  527.     server.register_function((lambda x, y: x + y), 'add')
  528.     server.serve_forever()
  529.  
  530.